package com.mebs.model.logistics;

import com.mebs.model.DimensionUnit;
import com.mebs.model.WeightUnit;
import com.mebs.model.AuditInfo;
import com.mebs.model.VolumeUnit;
import com.mebs.model.inventory.*;

import javax.persistence.*;
import java.util.Set;
import java.util.List;
import java.util.LinkedList;

import org.jt.jet.util.JetUtils;
import static org.hibernate.proxy.HibernateProxyHelper.getClassWithoutInitializingProxy;

/**
 * Created by Sergey Prasolov, sap@jensentechnologies.com Date: Apr 7, 2006, 1:56:56 PM
 */
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@Table(name = "OCEAN_CONTAINERS")
public class OceanContainer {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "Id")
    private Long id;

    @ManyToOne(optional = false)
    @JoinColumn(name = "OceanId")
    private Ocean ocean;

    @Column(name = "Type", nullable = false)
    private Integer containerType;

    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    @JoinColumn(name = "OceanContainerId")
    @OrderBy("number")
    private Set<Box> boxes;

    @Column(name = "Number", nullable = false)
    private String number;

    @Column(name = "DimL", nullable = true)
    private Double dimL;

    @Column(name = "DimW", nullable = true)
    private Double dimW;

    @Column(name = "DimH", nullable = true)
    private Double dimH;

    @Column(name = "DimUnit", nullable = true)
    private Integer dimUnit;

    @Column(name = "Volume", nullable = true)
    private Double volume;

    @Column(name = "volumeUnit", nullable = true)
    private Integer volumeUnit;

    @Column(name = "Weight", nullable = true)
    private Double weight;

    @Column(name = "WeightUnit", nullable = true)
    private Integer weightUnit;

    @Embedded
    private AuditInfo auditInfo;

    /**
     * Constructors
     */

    public OceanContainer()
    {

    }

    public OceanContainer(
        Ocean ocean,
        Integer containerType,
        String number,
        Double dimL,
        Double dimW,
        Double dimH,
        Integer dimUnit)
    {
        this(number, dimL, dimW, dimH, dimUnit, null, null, null, null);
//        this(number, dimL, dimW, dimH, dimUnit, null, null);
        this.ocean = ocean;
        this.containerType = containerType;
    }

    public OceanContainer(
        String number,
        Double dimL,
        Double dimW,
        Double dimH,
        Integer dimUnit,
        Double volume,
        Integer volumeUnit,
        Double weight,
        Integer weightUnit)
    {
        this.number = number;
        this.dimL = dimL;
        this.dimW = dimW;
        this.dimH = dimH;
        this.dimUnit = dimUnit;
        this.volume = volume;
        this.volumeUnit = volumeUnit;
        this.weight = weight;
        this.weightUnit = weightUnit;
    }

    /**
     * ********************** Getters-setters ***********************
     */

    public Long getId()
    {
        return id;
    }

    public void setId(Long id)
    {
        this.id = id;
    }

    public Ocean getOcean()
    {
        return ocean;
    }

    public void setOcean(Ocean ocean)
    {
        this.ocean = ocean;
    }

    public Integer getContainerType()
    {
        return containerType;
    }

    public void setContainerType(Integer containerType)
    {
        this.containerType = containerType;
    }

    public Set<Box> getBoxes()
    {
        return boxes;
    }

    public void setBoxes(Set<Box> boxes)
    {
        this.boxes = boxes;
    }

    public String getNumber()
    {
        return number;
    }

    public void setNumber(String number)
    {
        this.number = number;
    }

    public Double getDimL()
    {
        return dimL;
    }

    public void setDimL(Double dimL)
    {
        this.dimL = dimL;
    }

    public Double getDimW()
    {
        return dimW;
    }

    public void setDimW(Double dimW)
    {
        this.dimW = dimW;
    }

    public Double getDimH()
    {
        return dimH;
    }

    public void setDimH(Double dimH)
    {
        this.dimH = dimH;
    }

    public Integer getDimUnit()
    {
        return dimUnit;
    }

    public void setDimUnit(Integer dimUnit)
    {
        this.dimUnit = dimUnit;
    }

    public Double getVolume()
    {
        return volume;

    }

//    @Transient
//    public Double getVolume()
//    {
//        Double boxVolume = 0.0;
//        Double bVolume = null;
//
//        if (boxes != null) {
//            for (Box b : boxes) {
//                bVolume = b.getVolume();
//                if (bVolume != null) {
//                    boxVolume += bVolume;
//                }
//            }
//        }
//
//        if (boxVolume == 0.0) {
//            boxVolume = null;
//        }
//
//        return boxVolume;
//    }

    public void setVolume(Double volume)
    {
        this.volume = volume;
    }

    public Integer getVolumeUnit()
    {
        return volumeUnit;
    }

    public void setVolumeUnit(Integer volumeUnit)
    {
        this.volumeUnit = volumeUnit;
    }

    public Double getWeight()
    {
        return weight;
    }

    public void setWeight(Double weight)
    {
        this.weight = weight;
    }

    public Integer getWeightUnit()
    {
        return weightUnit;
    }

    public void setWeightUnit(Integer weightUnit)
    {
        this.weightUnit = weightUnit;
    }

    public AuditInfo getAuditInfo()
    {
        if (this.auditInfo == null) {
            this.auditInfo = new AuditInfo();
        }
        return auditInfo;
    }

    public void setAuditInfo(AuditInfo auditInfo)
    {
        this.auditInfo = auditInfo;
    }

    @Transient
    public boolean isDeletable()
    {
        return JetUtils.isEmpty(this.boxes);
    }

    @Override
    public String toString()
    {
        return this.getNumber() == null ? "" : this.getNumber();
    }

    @Transient
    public String getDimUnitString()
    {
        return dimUnit != null ? DimensionUnit.getObjectByType(dimUnit).getName() : "";
    }

    @Transient
    public String getVolumeUnitString()
    {
        return volumeUnit != null ? VolumeUnit.getObjectByType(volumeUnit).getName() : "";
        //return "";
    }

    @Transient
    public String getWeightUnitString()
    {
        return weightUnit != null ? WeightUnit.getObjectByType(weightUnit).getName() : "";
    }

    @Transient
    public String getTypeString()
    {
        return containerType != null ? OceanContainerType.getObjectByType(containerType).getName() : "";
    }

    @Transient
    public List<Box> getNotPackedBoxes()
    {
        List<Box> notPackedBoxes = new LinkedList<Box>();

        for (Box b : this.boxes) {
            if (b.getOverpackedBox() == null) {
                notPackedBoxes.add(b);
            }
        }

        return notPackedBoxes;
    }

    @Transient
    public boolean isPiece(Box item)
    {
        return (item instanceof RelocationPiece);

    }

    @Transient
    public boolean hasItem(Object item)
    {
        if (item instanceof RelocationPiece) {
            return this.hasPiece((RelocationPiece) item);
        }

        return false;
    }

    @Transient
    private boolean hasPiece(RelocationPiece piece)
    {
        if (JetUtils.isEmpty(this.boxes)) {
            return false;
        }

        return this.boxes.contains(piece);
    }

    @Transient
    public boolean isOrderUsed(AbstractOrder order)
    {
        if (order instanceof PurchaseOrder) {
            return isPOUsed((PurchaseOrder) order);
        } else if (order instanceof RelocationOrder) {
            return isROUsed((RelocationOrder) order);
        }
        return false;  // for a case (iav)
    }

    @Transient
    public boolean isPOUsed(PurchaseOrder po)
    {
        if (JetUtils.isEmpty(this.boxes)) return false;
        for (Box box : this.boxes) {
            if (box instanceof StructuredBox) {
                for (BoxItem boxItem : ((StructuredBox) box).getItems()) {
                    if (boxItem.getOrderItem().getOrder().equals(po)) {
                        return true;
                    }
                }
            }
        }
        return false;
    }

    @Transient
    public boolean isROUsed(RelocationOrder ro)
    {
        if (JetUtils.isEmpty(this.boxes)) return false;
        for (Box box : this.boxes) {
            if (box instanceof RelocationPiece) {
                if (((RelocationPiece) box).getOrder().equals(ro)) {
                    return true;
                }
            }
        }
        return false;
    }

/*
    @Transient
    @Deprecated
    public Integer getBoxedQuantity(BoxSubItem subItem)
    {
        if (JetUtils.isEmpty(boxes)) return 0;

        int qty = 0;

        for (Box box : getNotPackedBoxes()) {
            if (box instanceof StructuredBox)
                qty += ((StructuredBox) box).getItemQuantity(subItem);
            else if (box instanceof OverpackedBox)
                qty += ((OverpackedBox) box).getItemQuantity(subItem);
        }

        return qty;
    }

    @Transient
    @Deprecated
    public Integer getBoxedQuantity(OrderItem orderItem)
    {
        if (JetUtils.isEmpty(boxes)) return 0;

        int qty = 0;
        for (Box box : getNotPackedBoxes()) {
            if (box instanceof StructuredBox) {
                qty += ((StructuredBox) box).getItemQuantity(orderItem);
            } else if (box instanceof OverpackedBox) {
                qty += ((OverpackedBox) box).getItemQuantity(orderItem);
            }
        }

        return qty;
    }
*/

	@Transient
	public Box getNextBox(Box curItem){
		Box resBox = new StructuredBox();
		if (JetUtils.isEmpty(boxes)) return resBox;
		boolean isCur = false;

		for (Box b : this.boxes) {
			if(isCur){
				resBox = b;
				isCur = false;
			}
			if (b.equals(curItem)) {
                isCur = true;
            }
		}
		return resBox;
	}

	@Override
    public int hashCode()
    {
        if (id == null) return super.hashCode();
        return id.hashCode();
    }

    @Override
    public boolean equals(Object o)
    {
        if (o == null) return false;
        if (this == o) return true;
        if (id == null) return false;
        if (getClassWithoutInitializingProxy(this) != getClassWithoutInitializingProxy(o))
            return false;
        final OceanContainer that = (OceanContainer) o;
        return id.equals(that.getId());
    }

}
